package com.yyplatform.admin.infra.jpa;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.MapUtils;
import org.hibernate.query.sql.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;

import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.Query;
import lombok.extern.slf4j.Slf4j;

/**
 * Created on 2024-11-25
 */
@Slf4j
@Component
public class JpaSQLHelper {

    @PersistenceContext
    private EntityManager entityManager;


    public List getResultList(String sql, Map<String, Object> params) {
        Query query = entityManager.createNativeQuery(sql);
        if (MapUtils.isNotEmpty(params)) {
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                query.setParameter(entry.getKey(), entry.getValue());
            }
        }
        return query.getResultList();
    }


    public Object getSingleResult(String sql, Map<String, Object> params) {
        Query query = entityManager.createNativeQuery(sql);
        if (MapUtils.isNotEmpty(params)) {
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                query.setParameter(entry.getKey(), entry.getValue());
            }
        }
        query.unwrap(NativeQueryImpl.class).setResultListTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        return query.getSingleResult();
    }


    public int executeDelete(String sql, Map<String, Object> param) {
        Query nativeQuery = entityManager.createNativeQuery(sql);
        if (MapUtils.isNotEmpty(param)) {
            for (Map.Entry<String, Object> entry : param.entrySet()) {
                nativeQuery.setParameter(entry.getKey(), entry.getValue());
            }
        }
        return nativeQuery.executeUpdate();
    }


    public int executeUpdate(String sql, Map<String, Object> param) {
        Query nativeQuery = entityManager.createNativeQuery(sql);
        if (MapUtils.isNotEmpty(param)) {
            for (Map.Entry<String, Object> entry : param.entrySet()) {
                nativeQuery.setParameter(entry.getKey(), entry.getValue());
            }
        }
        return nativeQuery.executeUpdate();
    }


    public Page getPageResult(String sql, Map<String, Object> params, Pageable pageRequest) {
        Query nativeQuery = entityManager.createNativeQuery(sql);
        // 设置参数
        if (MapUtils.isNotEmpty(params)) {
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                nativeQuery.setParameter(entry.getKey(), entry.getValue());
            }
        }
        //        Assert.notNull(nativeQuery,"SQL执行");

        Long total = count(sql, params);

        if (total == null) {
            return null;
        }
        // 设置分页参数
        nativeQuery.setFirstResult((int) pageRequest.getOffset());
        nativeQuery.setMaxResults(pageRequest.getPageSize());

        //        nativeQuery.unwrap(org.hibernate.SQLQuery.class).setResultTransformer(Transformers
        //        .ALIAS_TO_ENTITY_MAP);
        List mapList = nativeQuery.getResultList();

        List<Map<String, Object>> content = total > pageRequest.getOffset() ? mapList : Collections.emptyList();

        return new PageImpl<>(content, pageRequest, total);
    }


    protected Long count(String sql, Map<String, Object> param) {
        String countSql = "select count(*) from (" + sql + ") a";
        Query countQuery = entityManager.createNativeQuery(countSql);

        // 设置参数
        if (MapUtils.isNotEmpty(param)) {
            for (Map.Entry<String, Object> entry : param.entrySet()) {
                countQuery.setParameter(entry.getKey(), entry.getValue());
            }
        }
        //        Assert.notNull(countQuery,"SQL执行");
        Long total = 0L;
        Object totalObj = countQuery.getSingleResult();
        try {
            if (totalObj != null) {
                if (totalObj instanceof BigDecimal) {
                    BigDecimal bd = (BigDecimal) totalObj;
                    total = bd.longValue();
                } else if (totalObj instanceof BigInteger) {
                    BigInteger bd = (BigInteger) totalObj;
                    total = bd.longValue();
                } else {
                    total = Long.parseLong(totalObj.toString());
                }
            }
        } catch (Exception e) {
            log.error("不支持该数据库count返回类型！！");
        }
        return total;
    }

}
